﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using System.Threading;
using System.Web;
using System.Xml;
using System.Xml.Xsl;

namespace FishScore
{
    public static class ExportHelper
    {
        /// <summary>
        /// Export format enumeration
        /// </summary>
        public enum ExportFormat : int
        {
            /// <summary>
            /// CSV
            /// </summary>
            CSV,

            /// <summary>
            /// DOC
            /// </summary>
            DOC,

            /// <summary>
            /// TXT
            /// </summary>
            TXT
        };

        /// <summary>
        /// 应用程序类型
        /// </summary>
        public enum ApplicationType : int
        {
            WindowsForm,
            Web
        }

        /// <summary>
        /// 导出SmartGridView的数据源的数据为Excel
        /// </summary>
        // <param name="dt">数据源</param>
        /// <param name="fileName">文件名</param>
        /// <param name="ApplicationType">应用宿主类型</param>
        public static void ExportDetails(DataTable dt, string fileName, ApplicationType ApplicationType)
        {
            ExportDetails(dt, ExportFormat.CSV, fileName, ApplicationType);
        }

        #region ExportDetails OverLoad : Type#1

        // Function  : ExportDetails
        // Arguments : DetailsTable, FormatType, FileName
        // Purpose     : To get all the column headers in the datatable and
        //               exorts in CSV / Excel format with all columns

        public static void ExportDetails(DataTable DetailsTable, ExportFormat FormatType, string FileName, ApplicationType ApplicationType)
        {
            try
            {
                if (DetailsTable.Rows.Count == 0)
                    throw new Exception("无数据可以导出");

                // Create Dataset
                DataSet dsExport = new DataSet("Export");
                DataTable dtExport = DetailsTable.Copy();
                dtExport.TableName = "Values";
                dsExport.Tables.Add(dtExport);

                // Getting Field Names
                string[] sHeaders = new string[dtExport.Columns.Count];
                string[] sFileds = new string[dtExport.Columns.Count];

                for (int i = 0; i < dtExport.Columns.Count; i++)
                {
                    sHeaders[i] = dtExport.Columns[i].ColumnName;
                    sFileds[i] = ReplaceSpecialChars(dtExport.Columns[i].ColumnName);
                }

                if (ApplicationType == ApplicationType.Web)
                {
                    Export_with_XSLT_Web(dsExport, sHeaders, sFileds, FormatType, FileName);
                }
                else if (ApplicationType == ApplicationType.WindowsForm)
                {
                    Export_with_XSLT_Windows(dsExport, sHeaders, sFileds, FormatType, FileName);
                }
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        #endregion ExportDetails OverLoad : Type#1

        #region ExportDetails OverLoad : Type#2

        // Function  : ExportDetails
        // Arguments : DetailsTable, ColumnList, FormatType, FileName
        // Purpose     : To get the specified column headers in the datatable and
        //               exorts in CSV / Excel format with specified columns

        public static void ExportDetails(DataTable DetailsTable, int[] ColumnList, ExportFormat FormatType, string FileName,
            ApplicationType ApplicationType)
        {
            try
            {
                if (DetailsTable.Rows.Count == 0)
                    throw new Exception("无数据可以导出");

                // Create Dataset
                DataSet dsExport = new DataSet("Export");
                DataTable dtExport = DetailsTable.Copy();
                dtExport.TableName = "Values";
                dsExport.Tables.Add(dtExport);

                if (ColumnList.Length > dtExport.Columns.Count)
                    throw new Exception("导出列不能大于总列数");

                // Getting Field Names
                string[] sHeaders = new string[ColumnList.Length];
                string[] sFileds = new string[ColumnList.Length];

                for (int i = 0; i < ColumnList.Length; i++)
                {
                    if ((ColumnList[i] < 0) || (ColumnList[i] >= dtExport.Columns.Count))
                        throw new Exception("导出列不能大于总列数");

                    sHeaders[i] = dtExport.Columns[ColumnList[i]].ColumnName;
                    sFileds[i] = ReplaceSpecialChars(dtExport.Columns[ColumnList[i]].ColumnName);
                }

                if (ApplicationType == ApplicationType.Web)
                {
                    Export_with_XSLT_Web(dsExport, sHeaders, sFileds, FormatType, FileName);
                }
                else if (ApplicationType == ApplicationType.WindowsForm)
                {
                    Export_with_XSLT_Windows(dsExport, sHeaders, sFileds, FormatType, FileName);
                }
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        #endregion ExportDetails OverLoad : Type#2

        #region ExportDetails OverLoad : Type#3

        // Function  : ExportDetails
        // Arguments : DetailsTable, ColumnList, Headers, FormatType, FileName
        // Purpose     : To get the specified column headers in the datatable and
        //               exorts in CSV / Excel format with specified columns and
        //               with specified headers

        public static void ExportDetails(DataTable DetailsTable, int[] ColumnList, string[] sHeaders, ExportFormat FormatType,
            string FileName, ApplicationType ApplicationType)
        {
            try
            {
                if (DetailsTable.Rows.Count == 0)
                    throw new Exception("There are no details to export");

                // Create Dataset
                DataSet dsExport = new DataSet("Export");
                DataTable dtExport = DetailsTable.Copy();
                dtExport.TableName = "Values";
                dsExport.Tables.Add(dtExport);

                if (ColumnList.Length != sHeaders.Length)
                    throw new Exception("ExportColumn List and Headers List should be of same length");
                else if (ColumnList.Length > dtExport.Columns.Count || sHeaders.Length > dtExport.Columns.Count)
                    throw new Exception("导出列不能大于总列数");

                // Getting Field Names
                string[] sFileds = new string[ColumnList.Length];

                for (int i = 0; i < ColumnList.Length; i++)
                {
                    if ((ColumnList[i] < 0) || (ColumnList[i] >= dtExport.Columns.Count))
                        throw new Exception("导出列不能大于总列数");

                    sFileds[i] = ReplaceSpecialChars(dtExport.Columns[ColumnList[i]].ColumnName);
                }

                if (ApplicationType == ApplicationType.Web)
                {
                    Export_with_XSLT_Web(dsExport, sHeaders, sFileds, FormatType, FileName);
                }
                else if (ApplicationType == ApplicationType.WindowsForm)
                {
                    Export_with_XSLT_Windows(dsExport, sHeaders, sFileds, FormatType, FileName);
                }
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        /// <summary>
        /// 导出SmartGridView的数据源的数据
        /// </summary>
        /// <param name="DetailsTable">数据源</param>
        /// <param name="columnNameList">导出的列的列名数组</param>
        /// <param name="sHeaders">导出的列标题数组</param>
        /// <param name="FormatType">导出文件的格式</param>
        /// <param name="FileName">输出文件名</param>
        /// <param name="ApplicationType">应用宿主类型</param>
        public static void ExportDetails(DataTable DetailsTable, string[] columnNameList, string[] sHeaders,
            ExportFormat FormatType, string FileName, ApplicationType ApplicationType)
        {
            List<int> columnIndexList = new List<int>();
            DataColumnCollection dcc = DetailsTable.Columns;

            foreach (string s in columnNameList)
            {
                columnIndexList.Add(GetColumnIndexByColumnName(dcc, s));
            }

            ExportDetails(DetailsTable, columnIndexList.ToArray(), sHeaders, FormatType, FileName, ApplicationType);
        }

        #endregion ExportDetails OverLoad : Type#3

        #region ExportDetails OverLoad : Type#3

        // Function  : ExportDetails
        // Arguments : DetailsTable, FormatType, FileName
        // Purpose     : To get all the column headers in the datatable and
        //               exorts in CSV / Excel format with all columns
        public static void ExportDetails(DataTableCollection DetailsTables, ExportFormat FormatType, string FileName, ApplicationType ApplicationType)
        {
            try
            {
                string NewFileName;

                foreach (DataTable DetailsTable in DetailsTables)
                {
                    if (DetailsTable.Rows.Count == 0)
                        throw new Exception("There are no details to export.");

                    NewFileName = FileName.Substring(0, FileName.LastIndexOf("."));
                    NewFileName += " - " + DetailsTable.TableName;
                    NewFileName += FileName.Substring(FileName.LastIndexOf("."));

                    // Create Dataset
                    DataSet dsExport = new DataSet("Export");
                    DataTable dtExport = DetailsTable.Copy();
                    dtExport.TableName = "Values";
                    dsExport.Tables.Add(dtExport);

                    // Getting Field Names
                    string[] sHeaders = new string[dtExport.Columns.Count];
                    string[] sFileds = new string[dtExport.Columns.Count];

                    for (int i = 0; i < dtExport.Columns.Count; i++)
                    {
                        sHeaders[i] = dtExport.Columns[i].ColumnName;
                        sFileds[i] = ReplaceSpecialChars(dtExport.Columns[i].ColumnName);
                    }

                    if (ApplicationType == ApplicationType.Web)
                    {
                        Export_with_XSLT_Web(dsExport, sHeaders, sFileds, FormatType, FileName);
                    }
                    else if (ApplicationType == ApplicationType.WindowsForm)
                    {
                        Export_with_XSLT_Windows(dsExport, sHeaders, sFileds, FormatType, FileName);
                    }
                }
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        #endregion ExportDetails OverLoad : Type#3

        #region Export_with_XSLT_Web

        // Function  : Export_with_XSLT_Web
        // Arguments : dsExport, sHeaders, sFileds, FormatType, FileName
        // Purpose   : Exports dataset into CSV / Excel format
        private static void Export_with_XSLT_Web(DataSet dsExport, string[] sHeaders, string[] sFileds, ExportFormat FormatType, string FileName)
        {
            try
            {
                // Appending Headers
                HttpContext.Current.Response.Clear();
                HttpContext.Current.Response.Buffer = true;
                HttpContext.Current.Response.ContentType = String.Format("text/{0}", FormatType.ToString().ToLower());
                HttpContext.Current.Response.AddHeader("content-disposition", String.Format("attachment;filename={0}.{1}", FileName, FormatType.ToString().ToLower()));
                //HttpContext.Current.Response.ContentEncoding = encoding;

                // XSLT to use for transforming this dataset.
                MemoryStream stream = new MemoryStream();
                XmlTextWriter writer = new XmlTextWriter(stream, Encoding.Default);

                CreateStylesheet(writer, sHeaders, sFileds, FormatType);
                writer.Flush();
                stream.Seek(0, SeekOrigin.Begin);

                XmlDataDocument xmlDoc = new XmlDataDocument(dsExport);
                XslCompiledTransform xslTran = new XslCompiledTransform();
                xslTran.Load(new XmlTextReader(stream));

                System.IO.StringWriter sw = new System.IO.StringWriter();
                xslTran.Transform(xmlDoc, null, sw);

                //Writeout the Content
                HttpContext.Current.Response.Write(sw.ToString());
                sw.Close();
                writer.Close();
                stream.Close();
                HttpContext.Current.Response.End();
            }
            catch (ThreadAbortException Ex)
            {
                string ErrMsg = Ex.Message;
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        #endregion Export_with_XSLT_Web

        #region Export_with_XSLT_Windows

        // Function  : Export_with_XSLT_Windows
        // Arguments : dsExport, sHeaders, sFileds, FormatType, FileName
        // Purpose   : Exports dataset into CSV / Excel format
        private static void Export_with_XSLT_Windows(DataSet dsExport, string[] sHeaders, string[] sFileds,
            ExportFormat FormatType, string FileName)
        {
            try
            {
                // XSLT to use for transforming this dataset.
                MemoryStream stream = new MemoryStream();
                XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8);

                CreateStylesheet(writer, sHeaders, sFileds, FormatType);
                writer.Flush();
                stream.Seek(0, SeekOrigin.Begin);

                XmlDataDocument xmlDoc = new XmlDataDocument(dsExport);
                XslCompiledTransform xslTran = new XslCompiledTransform();
                xslTran.Load(new XmlTextReader(stream));

                System.IO.StringWriter sw = new System.IO.StringWriter();
                xslTran.Transform(xmlDoc, null, sw);

                //Writeout the Content
                StreamWriter strwriter = new StreamWriter(FileName, false, Encoding.Default);
                strwriter.WriteLine(sw.ToString());
                strwriter.Close();

                sw.Close();
                writer.Close();
                stream.Close();
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        #endregion Export_with_XSLT_Windows

        #region CreateStylesheet

        // Function  : WriteStylesheet
        // Arguments : writer, sHeaders, sFileds, FormatType
        // Purpose   : Creates XSLT file to apply on dataset's XML file
        private static void CreateStylesheet(XmlTextWriter writer, string[] sHeaders, string[] sFileds, ExportFormat FormatType)
        {
            try
            {
                // xsl:stylesheet
                string ns = "http://www.w3.org/1999/XSL/Transform";
                writer.Formatting = Formatting.Indented;
                writer.WriteStartDocument();
                writer.WriteStartElement("xsl", "stylesheet", ns);
                writer.WriteAttributeString("version", "1.0");
                writer.WriteStartElement("xsl:output");
                writer.WriteAttributeString("method", "text");
                writer.WriteAttributeString("version", "4.0");
                writer.WriteEndElement();

                // xsl-template
                writer.WriteStartElement("xsl:template");
                writer.WriteAttributeString("match", "/");

                // xsl:value-of for headers
                for (int i = 0; i < sHeaders.Length; i++)
                {
                    writer.WriteString("\"");
                    writer.WriteStartElement("xsl:value-of");
                    writer.WriteAttributeString("select", "'" + sHeaders[i] + "'");
                    writer.WriteEndElement(); // xsl:value-of
                    writer.WriteString("\"");
                    if (i != sFileds.Length - 1) writer.WriteString((FormatType == ExportFormat.CSV) ? "," : "    ");
                }

                // xsl:for-each
                writer.WriteStartElement("xsl:for-each");
                writer.WriteAttributeString("select", "Export/Values");
                writer.WriteString("\r\n");

                // xsl:value-of for data fields
                for (int i = 0; i < sFileds.Length; i++)
                {
                    writer.WriteString("\"");
                    writer.WriteStartElement("xsl:value-of");
                    writer.WriteAttributeString("select", sFileds[i]);
                    writer.WriteEndElement(); // xsl:value-of
                    writer.WriteString("\"");
                    if (i != sFileds.Length - 1) writer.WriteString((FormatType == ExportFormat.CSV) ? "," : "    ");
                }

                writer.WriteEndElement(); // xsl:for-each
                writer.WriteEndElement(); // xsl-template
                writer.WriteEndElement(); // xsl:stylesheet
                writer.WriteEndDocument();
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
        }

        public static string ReplaceSpecialChars(string input)
        {
            // space     ->     _x0020_
            // %        ->     _x0025_
            // #        ->    _x0023_
            // &        ->    _x0026_
            // /        ->    _x002F_

            input = input.Replace(" ", "_x0020_")
                .Replace("%", "_x0025_")
                .Replace("#", "_x0023_")
                .Replace("&", "_x0026_")
                .Replace("/", "_x002F_");

            return input;
        }

        /// <summary>
        /// 根据数据列的列名取数据列的列索引
        /// </summary>
        /// <param name="dcc">数据列集合</param>
        /// <param name="columnName">数据列的列名</param>
        /// <returns></returns>
        public static int GetColumnIndexByColumnName(DataColumnCollection dcc, string columnName)
        {
            int result = -1;

            for (int i = 0; i < dcc.Count; i++)
            {
                if (dcc[i].ColumnName.ToLower() == columnName.ToLower())
                {
                    result = i;
                    break;
                }
            }

            return result;
        }

        #endregion CreateStylesheet
    }
}